from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException,TimeoutException,StaleElementReferenceException,NoSuchWindowException
from selenium.webdriver.common.action_chains import ActionChains
import json,time,os,re,traceback,io,copy
import requests,bs4
from timetransfer import timetransfer
from PIL import Image
from relay import map_name_class
from easyExcel import EasyExcel
from winhand import Winhand
from mysql import MySql
from compress_img import CompressImage
from functools import wraps
log_url ={
    'baidu': ('https://baijiahao.baidu.com/','******','******'),
    'yidianzixun': ('https://mp.yidianzixun.com/','******','******'),#密码错误，异地报错，需要手机验证
    'sina': ('http://mp.sina.com.cn/','******','******'),#建议用密码登录，登录后有弹窗
    'sohu': ('http://mp.sohu.com','******','******'),#需要qq验证，可以cookie登陆
    '163': ('http://mp.163.com/','******','******'),#标题字数在11-30
    
    'dayu': ('https://mp.dayu.com/','******','******'),#
    'ifeng': ('http://fhh.ifeng.com/login','******','******'),#QQ，拷贝cookie时，取.ifeng.com的域名
    'youcheyihou': ('http://mp.youcheyihou.com','******','******'),
    'qutoutiao': ('https://mp.qutoutiao.net/','******','******'),
    'weibo': ('https://weibo.com/','******','******'),#建议用密码登录
    'toutiao': ('https://mp.toutiao.com/','******',''),#手机验证，建议cookie登陆
    #登陆存在问题的
    'autohome': ('https://chejiahao.autohome.com.cn/','******','******'),#cookie登陆，有验证，图片需要大与560*315，长宽均大于
    'maiche': ('http://media.maiche.com/','******','******'),
    #'weixin': ('https://mp.weixin.qq.com/','','******'),#微信验证，建议cookie登陆
    'qq':('https://om.qq.com/article/index','******','******'),
}

publish_url = {
    'youcheyihou': 'http://mp.youcheyihou.com/#/article-edit',
    'autohome': 'https://chejiahao.autohome.com.cn/My/AuthorArticles/add/0#pvareaid=2808351',
    'baidu': 'https://baijiahao.baidu.com/builder/rc/edit?type=news&app_id=1591384705840207',
    'qutoutiao': 'https://mp.qutoutiao.net/publish-content/article',
    '163': 'http://mp.163.com/article/postpage/W8567100657272114912?wemediaId=W8567100657272114912',
    'sina': 'http://mp.sina.com.cn/main/editor?vt=4#/SendArt/Edit', 
    'dayu': 'https://mp.dayu.com/dashboard/article/write?spm=a2s0i.db_contents.menu.3.67c73caarUGcXk',
    'yidianzixun': 'https://mp.yidianzixun.com/#/Writing/articleEditor',
    'maiche': 'http://media.maiche.com/manage/fun/publish.html',
    'sohu': 'https://mp.sohu.com/mpfe/v3/main/news/addarticle?contentStatus=1',
    'ifeng': 'http://fhh.ifeng.com/publish/article',
    'toutiao': 'https://mp.toutiao.com/profile_v3/graphic/publish',
    'weibo': 'https://card.weibo.com/article/v3/editor#/draft',
}
query_url={
    'baidu': 'https://baijiahao.baidu.com/builder/rc/content?type=&collection=&pageSize=10&currentPage=1&search=&app_id=1591384705840207',
    'weibo': 'https://weibo.com/5646432272/profile?rightmod=1&wvr=6&mod=personinfo&is_all=1',
    'sina': 'http://mp.sina.com.cn/#/ContentList',
    'sohu': 'https://mp.sohu.com/mpfe/v3/main/news/articlelist',
    '163': 'http://mp.163.com/index.html#/article/manage?wemediaId=W8567100657272114912',
    'dayu': 'https://mp.dayu.com/dashboard/contents',
    'ifeng': 'http://fhh.ifeng.com/manage/originalArticle',
    'youcheyihou': 'http://mp.youcheyihou.com/#/article-original',
    'qutoutiao': 'https://mp.qutoutiao.net/content-manage/article?status=&page=1&title=&submemberid=&nickname=&start_date=&end_date=&isMotherMember=false',
    'toutiao': 'https://mp.toutiao.com/profile_v3/graphic/articles',
    'yidianzixun': 'https://mp.yidianzixun.com/#/ArticleManual/original/publish',
    'autohome': 'https://chejiahao.autohome.com.cn/My/Info?r=564765768',
    #'weixin': '',
    'maiche': 'http://media.maiche.com/manage/fun/article.html',
    'qq': 'https://om.qq.com/article/articleManage?stype=0',
}
map_zh_eng = {
    '百家号':'baidu',
    '网易号':'163',
    '新浪微博':'weibo',
    '新浪看点':'sina',
    '大风号':'ifeng',
    '大鱼号':'dayu',
    '趣头条':'qutoutiao',
    '搜狐号':'sohu',
    '有车号':'youcheyihou',
    '车友号':'maiche',
    '微信号':'weixin',
    '一点号':'yidianzixun',
    '头条号':'toutiao',
    '车家号': 'autohome',
    '企鹅号': 'qq',

}
map_eng_zh = dict(zip(map_zh_eng.values(),map_zh_eng.keys()))
class Auto_Publish():
    
    def __init__(self,driver=None):
        chrome_options = Options()
        chrome_options.add_argument(r"user-data-dir=C:\Users\Administrator\AppData\Local\Google\Chrome\User Data_1")
        prefs = {'profile.default_content_setting_values' :{'notifications' : 2}}
        chrome_options.add_experimental_option('prefs',prefs)
        #chrome_options.add_argument("window-size=1024,768")
        if not driver:
            self.driver = webdriver.Chrome(options=chrome_options, executable_path=\
                r'C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\Tools\chromedriver_win32\chromedriver.exe')
        else:
            self.driver = driver
        #self.driver.delete_all_cookies()
        #print(self.driver.get_cookies())
        self.message = dict()
        #self.driver.maximize_window()
        self.webs = {}
        self.handle_dict = {}
        self.main_handle = ''
        self.collect_message={}
        #路径设置
        self.main_path = r'C:\Users\Administrator\Desktop\test\公众号'
        self.cover_path = r'C:\Users\Administrator\Desktop\test\公众号\图片'
        self.report_path = r'C:\Users\Administrator\Desktop\test\公众号\报告'
        self.report_template_path = r'C:\Users\Administrator\Desktop\test\公众号\报告\统一模版.xlsx'
        self.message_cache_path = os.path.join(self.report_path,'message.json')#用来缓存上一次分析的文章的信息
        self.collect_info = os.path.join(self.report_path,'collect_info.json')#用来缓存上次收集到的链接信息
        self.msg_path = r'C:\Users\Administrator\Desktop\python\习题\项目\cookies\msg\msgid.json'
        self.content_for_tag_path = r'C:\Users\Administrator\Desktop\python\习题\项目\publish_news\content.txt'
        self.branch_path = r'C:\Users\Administrator\Desktop\test\公众号\报告\branch.json'
        #路径

############################ tools ######################################################### 
#login
    def find(self,locator,method=By.XPATH):
        return self.driver.find_element(method,locator)

    def finds(self,locator,method=By.XPATH):
        return self.driver.find_elements(method,locator)

    def _js_click(self,element):
        self.driver.execute_script("arguments[0].click()",element)

    def switch_to_frame(self):
        frame = self._wait_for(4,(By.XPATH,'.//iframe'))
        self.driver.switch_to.frame(frame)

    def login_by_hand(self,logurl,web_name,ready=False):#
        if not ready:
            self.driver.get(logurl)
        else:
            while True:
                command = input("Please login by hand,\nand if you loggedin,tap Enter.")
                if command == 'q' or command == 'Q':
                    break
                if self.get_cookies(web_name):#get_cookies函数：如果cookie不为空返回True，并且保存
                    return 
                
    def is_login(self):
        self.driver.implicitly_wait(10)
        try:
            self._wait_for(2,(By.XPATH,'//*[contains(text(),"帮宁工作室")]'))
        except Exception:
            return False
        return True


    def get_uniform_name(self,title):#只适用于首页
        if '百家号' in title:
            return 'baidu' 
        elif '微博' in title:
            return 'weibo'
        elif '新浪' in title:
            return 'sina'
        elif '搜狐' in title:
            return 'sohu'
        elif '网易' in title:
            return '163'
        elif '大鱼' in title:
            return 'dayu'
        elif '大风' in title:
            return 'ifeng'
        elif '有车' in title:
            return 'youcheyihou'
        elif '趣头条' in title:
            return 'qutoutiao'
        elif '头条号' in title:
            return 'toutiao'
        elif '一点号' in title:
            return 'yidianzixun'
        elif '车友头条' in title:
            return 'maiche'
        elif '车家号' in title:
            return 'autohome'
        else:
            print('网站 %s 没有对应的统一命名。\n' %title)
            return None
        
    def get_handle_dict(self):
        handle_dict = dict()
        for i in self.driver.window_handles:
            self.driver.switch_to.window(i)
            domain = self.driver.current_url
            unifo_name = self.get_keyword_from_domain(domain)
            if not unifo_name:
                print(' %s 的域名中没有关键字。\n' %self.driver.title)
            if unifo_name:
                handle_dict[unifo_name] = i
        return handle_dict
    
    def get_keyword_from_domain(self,domain):
        end = domain.find('.com')
        if end==-1:
            end = domain.find('.net')
            if end == -1:
                print('域名分析中中没有关键字。\n')
                return False
        start = domain.rfind('.',0,end)
        if start<0:
            start = domain.rfind('/',0,end)
        start += 1
        name = domain[start:end]
        return name
#login
#collect_info

    def file_name(self,title):#获取简化标题
        try:
            res = re.search(r'.*?(\|)\s?(?P<simple_title>.+)',title).group('simple_title')
        except AttributeError:
            return title
        #当么标题中没有|时，匹配值为空
        if not res:
            res = title
        return res

    def _make_img_file(self,title):
        path = self.cover_path
        file_path = os.path.join(path,title)
        os.mkdir(file_path)
        return file_path

    def reverse_dict(self,Dict):
        return dict(zip(Dict.values(),Dict.keys()))

    def _collect_urls(self,Dict,title,full_message=False):
        urls = {}
        for i in Dict:
            self.driver.switch_to.window(Dict[i])
            try:
                message = map_name_class(i)(self.driver).collect_info(title)
            except TimeoutException:
                print('%s搜集信息超时。\n' %map_eng_zh[i])
                message={}
            try:
                #print('%s:%s\n' %(message['title'],message['url']))
                urls[i] = (message['title'],message['url'])
            except (KeyError,TypeError):
                urls[i] = ('无','无')
        if full_message:
            return message
        else:
            return urls

    def collect_main_urls(self,generate_report=True):
        map_eng_zh = self.reverse_dict(map_zh_eng)
        self.message['source'] = 'weixin'
        message = self.get_message()
        try:
            message['source']
        except KeyError:
            message['source'] = 'weixin'
            message['title'] = '这是一个title'

        need = ['sina','baidu','sohu','yidianzixun','163','maiche']
        for i in need:
            self.open_new_window(query_url[i],quick_model=True)
        D = self.get_handle_dict()
        while True:
            if generate_report:
                try:
                    num = int(input('\n请输入搜索文章数: （回车退出）\n'))
                except ValueError:
                    return
            else:
                num = 1
            
            All = []
            for i in range(num):

                if message['source'] == self.message['source']:
                    title = input('请输入标题关键词：（回车默认收集各个平台第一篇文章，按q退出）\n')
                    # ans = input('你想搜索的是———%s这篇文章吗？(回车确认，如不是，输入关键字，输入q退出)\n' %message['title'])
                    # if not ans:
                    #     title =  self.file_name(message['title'])
                    # else:
                    #     title = ans
                if title=='q' or title=='Q':
                    return
                res  = self._collect_urls(D,title)
                All.append(res)
            if generate_report:
                for i in res:
                    print('\n——%s——:\n' %map_eng_zh[i])
                    print('这是今天帮宁工作室的更新，麻烦老师推荐一下。\n')
                    for j in All:
                        print('%s\n%s' %(j[i][0],j[i][1]))
            else:
                for i in res:
                    print('\n——%s——:\n' %map_eng_zh[i])
                    for j in All:
                        print('标题:%s\n链接:%s' %(j[i][0],j[i][1]))
    
    def _save_in_excel(self,read_count=False):
        "self.collect_message是一个嵌套字典，外层字典的键是统一的平台名称，值包含各种信息的字典"
        save_path = self.report_template_path
        if not self.collect_message:
            try:
                self.collect_message=self.message['collect_message']
            except KeyError:
                print('信息汇总中没有链接收集信息。\n')
                return

        web_name_column = 2
        item_start_row = 2
        date_column = 4
        title_column = 5
        url_column = 6
        read_count_column = 7
        sheet = 'Sheet1'
        Excel = EasyExcel(save_path)
        item_row = item_start_row
        for i in self.collect_message:
            try:
                title = self.collect_message[i]['title']
                if title:
                    break
            except KeyError:
                pass
        if self.message['source']=='weixin':
            try:
                title = self.collect_message['qq']['title']
            except KeyError:
                pass
            try:
                if not self.collect_message['weixin']:
                    self.collect_message['weixin'] = self._get_message_from_mysql(title)
            except KeyError:
                self.collect_message['weixin'] = self._get_message_from_mysql(title)

        date = timetransfer().s2f(time.time(),'%m{m}%d{d}')
        while True:
            web_name = Excel.getCell(sheet,item_row,web_name_column)
            if not web_name:
                break
            unifor_name = map_zh_eng[web_name]
            try:
                Excel.setCell(sheet,item_row,url_column,self.collect_message[unifor_name]['url'])
                try:
                    Excel.setCell(sheet,item_row,date_column,self.collect_message[i]['date'])
                except Exception:
                    Excel.setCell(sheet,item_row,date_column,date)
                Excel.setCell(sheet,item_row,title_column,self.collect_message[unifor_name]['title'])
                if read_count:
                    read_counts = self.collect_message[unifor_name]['read_counts']
                    if read_counts>9:
                        Excel.setCell(sheet,item_row,read_count_column,read_counts)
            except (KeyError,TypeError):
                pass
            item_row += 1

        main_path = os.path.split(save_path)[0]
        title = self._delete_illegal_char_in_title(title)
        new_path = os.path.join(main_path,'%s.xlsx' %title)
        Excel.save(new_path)
        print(new_path)
        Excel.close()

    def _delete_illegal_char_in_title(self,title):
        title = re.sub(r'\\','',title)
        title = re.sub(r'/','',title)
        title = re.sub(r'\|','',title)
        return title
    
    def save_last_message_in_excel(self,read_count=False):
        "若要记载阅读量，请把read_count设为True"
        self.message=self.get_collect_info()
        self._save_in_excel(read_count=read_count)

    def _open_webs(self):
        if self.message['model']=='publish':
            open_list = publish_url
        elif self.message['source'] == 'weixin':
            open_list = query_url
        for i in open_list:
            self.open_new_window(open_list[i],quick_model=True)
            time.sleep(1)

    def collect_all_urls_and_save(self,title=None,read_count=False,handle_dict=None,query_ready=True,from_weixin=False):
        "handle_dict参数为None既打开query也创建字典，query_ready为False（非默认值）会重新加载。"
        print('如果已经存在各个平台页面，但没有转到查询界面，请输入handle_dict与query_ready=False；\n')
        print('如果已经存在各个平台页面，并转到，请直接输入handle_dict。\n')
        print('x-x-'*15)
        self.message['model'] = 'collect'
        source = input('请告知文章来源，如果是来自微信，请输入1；\n如果是来自本地，请输入2：（回车退出）\n')
        if source=='1':
            self.message['source'] = 'weixin'
        elif source=='2':
            self.message['source'] = 'tencent'
        elif not source:
            return 
        else:
            print('输入错误。\n')
            return 

        if title==None:
            title = input('请输入标题关键词：（回车默认收集各个平台第一篇文章）\n')

        if not read_count:
            ans = input('是否需要保存阅读量？（回车默认不保存，输入任意一个字母表示保存）\n')
            if ans:
                read_count=True

        self.get_webs()
        if not handle_dict:
            need = list(log_url.keys())
            if self.message['source'] == 'tencent':
                need.remove('qq')
            for i in need:
                self.open_new_window(query_url[i],quick_model=True)
                time.sleep(1)
            self.refresh_handle_dict()
            #handle_dict = self.get_handle_dict()
            if not self.check_logged():
                ans = input('存在的登陆问题。(如已解决请按回车，如退出请按任意一个字母。)\n')
                if ans:
                    return
        else:
             self.refresh_handle_dict()

        if not query_ready:
            
            for i in self.handle_dict:
                self.driver.switch_to.window(self.handle_dict[i])
                self.driver.get(query_url[i])


        for i in self.handle_dict:
            self.driver.switch_to.window(self.handle_dict[i])
            try:
                res = self.webs[i].collect_info(title,read_count=read_count)
            except TimeoutException:
                print('%s搜集信息存在超时。' %map_eng_zh[i])
                res={}
            self.collect_message[i] = res

        self._save_message()

        self._save_in_excel(read_count=read_count)

    def get_message(self):
        path=self.message_cache_path
        res = json.loads(open(path).read())
        res['new'] = False
        try:
            res['source']
        except KeyError:
            ans=input('请输入来源，‘1’表示来微信，‘2’表示来自腾讯。（按任意字母退出）\n')
            if ans=='1':
                res['source']='weixin'
            elif ans=='2':
                res['source']='tencent'
            else:
                print('已退出。\n')
        return res

    def _save_message(self,collect_message=None):
        save_path=self.message_cache_path
        if collect_message:
            self.collect_message = collect_message
        
        if self.message['model']=='collect':
            save_path=self.collect_info
            self.message['collect_message']=self.collect_message
            with open(save_path,'w') as f:
                f.write(json.dumps(self.message))
            return
        else:
            with open(save_path,'w') as f:
                f.write(json.dumps(self.message))

            if self.message['source']=='weixin' and self.message['model'] == 'publish' and self.message['new']:
                core_message = self._generate_info_for_mysql()
                self._save_in_mysql(core_message)
                # Ms = MySql()
                # Ms.add('wechat_news',core_message)
                # Ms.close()
                # print('基本信息已保存入数据库。\n')
    
    def _generate_info_for_mysql(self,message=None):
        if not message:
            message = self.message

        core_message={}
        core_message['title'] = message['raw_title']
        for i in ('url','date'):
            core_message[i] = message[i]
        return core_message

    def _save_in_mysql(self,info=None):
        if not info:
            info = self._generate_info_for_mysql()
        Ms = MySql()
        try:
            Ms.add('wechat_news',info)
        except AttributeError:
            print('将信息保存入数据库出现错误。\n')
            return 
        Ms.close()
        print('基本信息已保存入数据库。\n')

    def _get_message_from_mysql(self,title):
        ms = MySql()
        res={}
        title = self.file_name(title)
        try:
            query_res = ms.query(('title',title))
            outcome = query_res[-1]
            if len(query_res) > 1:
                print('搜到多个结果。默认选择时间最近的一个。')
        except IndexError:
            print('没有搜到结果')
            return res
        fmt='%m-%d'
        
        res['title'] = outcome[1]
        res['url'] = outcome[2]
        res['date'] = outcome[3].strftime(fmt)
        ms.close()
        return res

    def get_collect_info(self):
        path=self.collect_info
        return json.loads(open(path).read())



#new_essay
    def search_weixin_essay(self):
        "出现迭代错误后，记得把essay_id加1,提供标题，导语，封面绝对路径，文章链接"
        msg_path=self.msg_path
        url = 'https://weixin.sogou.com/'
        self.open_new_window(url)
        self.driver.delete_all_cookies()

        account_name = '帮宁工作室'
        self.driver.find_element_by_xpath('//input[@id="query"]').send_keys(account_name)
        select_account_search = self._wait_for(3,(By.XPATH,'//input[@value="搜公众号"]'))
        self.compulsive_click(select_account_search)

        weixin_account = 'gbngzs'
        target = self._wait_for(3,(By.XPATH,'//label[text()="%s"]/../..//a' %weixin_account))
        self.compulsive_click(target)#会弹出新窗口
        self.driver.close()
        self.driver.switch_to.window(self.get_new_handle())

        if os.path.exists(msg_path):
            essay_id = json.loads(open(msg_path,'r').read())
        else:
            essay_id = int(input('Please input msgid:(like 1000000316)\n'))
            with open(msg_path,'w') as f:
                f.write(json.dumps(essay_id))
        while True:
            try:
                self._wait_for(3,(By.XPATH,'.//div[@id="history"]/div[@class="weui_msg_card"]'))
                essay_list = self.driver.find_elements_by_xpath('.//div[@id="history"]/div[@class="weui_msg_card"]')
                break
            except TimeoutException:
                input('可能有验证码。解决后请回车。\n')
                try:
                    self._wait_for(3,(By.XPATH,'.//em[text()="帮宁工作室"]/..')).click()
                    self.search_handle_by_title('帮宁工作室')#搜索并转到并返回结果句柄
                except TimeoutException:
                    pass
        all_msg_id = []
        
        for i in essay_list:
            msgid = i.find_element_by_xpath('.//div[contains(@class,"appmsg")]').get_attribute('msgid')
            all_msg_id.append(int(msgid))
        for i in all_msg_id:
            if i > essay_id:
                print('有新的文章。\n')
                essay_id = i
                break
            else:
                print('没有新的文章。\n')
                return 


        new_essay_list = self.driver.find_elements_by_xpath('.//div[@id="history"]//div[@msgid="%d"]' %essay_id)
        essay_num = 1
        for essay in new_essay_list:
            self.message = {}
            message  = {}
            style = essay.find_element_by_xpath('./span').get_attribute('style')
            cover_url = style[style.find('http'):style.rfind('jpeg') + 4]
            cover = requests.get(cover_url)
            cover.raise_for_status()
            date = time.strftime("%Y-%m-%d",time.localtime())
            cover_path = r'C:\Users\Administrator\Desktop\test\公众号\图片\%s-%d-%d.jpg' %(date,essay_num,essay_id)
            with open(cover_path,'wb') as f:
                f.write(cover.content)
            raw_title = essay.find_element_by_xpath('.//h4').text
            start = raw_title.find('GBN')
            message['title'] = raw_title[start:]
            #message['win_title'] = self.file_name(message['title'])
            message['introduce'] = essay.find_element_by_xpath('.//p').text
            message['window'] = self.driver.current_window_handle
            message['cover_path'] = cover_path
            message['target_url'] = 'https://mp.weixin.qq.com' + essay.find_element_by_xpath('.//h4').get_attribute('hrefs')
            self.message = message

            self._check_img_and_title()
            #标题不符合要即时输入修改，图片不符合要求，会用key——'change_cover'的bool值标记
            if self.message['change_cover']:
                message['imgs_path'] = self._make_img_file(message['win_title'])##
            self._click_into_essay()
            #获取一级标题
            message['heading'] = self._get_heading_text()
            #增加作者，复制正文
            self.message['tags'] = self.generate_tags()
            yield self.message
            essay_num += 1
            self.driver.switch_to.window(message['window'])#自动返回所在标签页
        with open(msg_path,'w') as f:
            f.write(json.dumps(essay_id))

    def _click_into_essay(self,platform='weixin'):#返回作者，写入纯文本，并选中全文，ctr_C
        self.open_new_window(self.message['target_url'])
        self.message['platform'] = platform
        if platform == 'weixin':
            author = self._strip_author()
            paras = self.driver.find_elements_by_xpath('//div[@id="js_content"]/p/span')
            #将文章写入txt,以便后来生成tag
            content_path = r'C:\Users\Administrator\Desktop\python\习题\项目\publish_news\content.txt'
            with open(content_path,'w') as f:
                for para in paras:
                    text = para.text
                    if text:
                        f.write(text.encode("gbk", 'ignore').decode("gbk", "ignore"))
                    
            #将每个图片载入完整
            self.message['imgs_num'] = self._load_full_page()
            # 可惜这个地址是webp格式的，如果需要下载，还是将其粘贴到其他平台上再保存到本地

            self._select_area()
            if len(author)<11:
                self.message['author']  = author
            else:
                print('作者名字长度超过10个字符。\n')

    def change_essay_version(self,dayu_handle):
        pass

    def generate_tags(self):
        file_path = self.content_for_tag_path
        content = open(file_path,'rb').read().decode("gbk", "ignore")
        import jieba.analyse
        tags = jieba.analyse.extract_tags(content,topK=5)
        return tags

    def _delete_num_with_circle(self,title):
        no_use = []
        res = title
        for i in title:
            if '\u2460'<= i <= '\u32bf':
                no_use.append(i)
        

        nums = len(no_use)
        if nums:
            no_use = list(set(no_use))
            for i in no_use:
                res = res.replace(i,'')
            print('#####存在%d个带圈数字，已删除。' %nums)
            print('新标题为：%s' %res)
        return res

    def _add_forhead(self,title):
        normal_match=['日常','特写','观察','专题','访谈','观点']
        special_match = ['设计','联盟','逝者','汽车记忆']
        if 'GBN' not in title and '|' in title:
            for i in normal_match:
                if i == title[:2]:
                    title = 'GBN' + title
                    break
            else:
                for i in special_match:
                    if i == title[:2]:
                        return title
                ans = input('是否添加“GBN特写”? (按任意字母确定，回车取消。)\n')
                if ans:
                    title = re.sub(r'\|\s','',title)
                    title = 'GBN特写 | ' + title

            return title
        else:
            return title

    def _get_byte_size(self,title):
        f = io.BytesIO()
        Bytes = f.write(title.encode('gbk'))
        f.close()
        return Bytes

    def _check_img_and_title(self):
        #11-30字的标题，2比特算一个字符。封面长宽分别要大于560*315，长宽比最好是3:2
        #title_path=r'C:\Users\Administrator\Desktop\python\习题\项目\publish_news\title.txt'
        self.message['raw_title'] = self.message['title'].strip()

        self.message['title'] = self._delete_num_with_circle(self.message['title'])
        self.message['title'] = self._add_forhead(self.message['title'])

        num_size = len(self.message['title'])

        byte_size = self._get_byte_size(self.message['title'])//2
        if 10<byte_size and num_size<31:
            print('标题字数符合要求。\n')
        else:
            if byte_size<=10:
                new_title = input('标题：%s 的字数不符合要求，少了%d个字请手动输入。\n' %(self.message['title'],11-byte_size))
            else:
                new_title = input('标题：%s 的字符数大于30，多了%d个字请手动输入。\n' %(self.message['title'],num_size-30))
            self.message['title'] = new_title


        if len(self.message['introduce'])>44:
            print('#####导语过长，需要在微博上修改。\n')

        res = self._check_cover_size(self.message['cover_path'])
        self.message['change_cover'] = res
        
    def _check_cover_size(self,img_path):
        bt_size = os.path.getsize(img_path)/1024
        if bt_size>500:
            self.message['cover_path'] = CompressImage(img_path,500).do_it()
            #print('封面大于500Kb。')
        cover = Image.open(img_path)
        if cover.size[0] > 560 and cover.size[1] >315:
            print('封面大小基本满足要求。\n')
            #message['change_cover']  = False
            ration = cover.size[0]/cover.size[1]
            if ration<1.32:
                print('#####封面宽长比略低，可能在封面剪切时需要手动修改。\n')
            return False
        else:
            x_margin = cover.size[0] - 560
            y_margin = cover.size[1] - 315
            print('#####封面大小不满足要求。')
            print('宽与标准相差%dpix,长与标准相差%dpix。\n' %(x_margin,y_margin))
            #message['change_cover']  = True
            return True
    
    def _check_author_is_too_long(self,author):
        if len(author)<11:
            return author
        else:
            author = input('作者名字:%s 长度超过10个字符,请修改后输入。\n' %author)
            return author  
    
    def _select_area_1(self,execute=True):
        start = self.driver.find_element_by_xpath('//div[@id="js_content"]/p')
        paras = self.driver.find_elements_by_xpath('.//div[@id="js_content"]/p')
        i=0
        end=None
        while True:
            i-=1
            if '。' in paras[i].text \
                or '？' in paras[i].text \
                or '！' in paras[i].text \
                or '?' in paras[i].text \
                or '!' in paras[i].text \
                or '……' in paras[i].text:
                end = paras[i]
                print('最后一段是:\n%s\n' %paras[i].text)
                #self.message['end_loaction_y'] = end.location['y'] + end.rect['height']
                break
        if execute:
            y_margin = end.rect['height'] + 15
            d = ActionChains(self.driver).move_to_element_with_offset(end,300,y_margin).click_and_hold()
            for para in paras[i:0:-3]:
                d.move_to_element_with_offset(para,300,y_margin).pause(0.3)#往一段的中部向上移动一行
            d.move_to_element_with_offset(start,-21,5).release().\
                key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()

    def display_element(self,element):
        self.driver.execute_script ("arguments[0].style=arguments[1]",element,"display: none;")

    def _select_area(self,execute=True,load_imgs=True):
        if load_imgs:
            self._load_full_page()

        paras = self.driver.find_elements_by_xpath('.//div[@id="js_content"]/p')
        i=0
        end = None
        while True:
            i-=1
            if '。' in paras[i].text \
                or '？' in paras[i].text \
                or '！' in paras[i].text \
                or '?' in paras[i].text \
                or '!' in paras[i].text \
                or '……' in paras[i].text:
                end = paras[i]
                print('最后一段是:\n%s\n' %end.text)
                end.location_once_scrolled_into_view
                #self.message['end_loaction_y'] = end.location['y'] + end.rect['height']
                break
        j = len(paras)+i
        end_location_y = end.location['y']
        if execute:
            head_displayed_paras = self.finds('.//div[@id="img-content"]/*')
            z = 0
            for i in head_displayed_paras:
                if i.get_attribute('id')=='js_content':
                    break
                else:
                    z+=1
                    #self.display_element(i)

            body_displayed_para = self.finds('.//div[@class="qr_code_pc"]')
            #可能有修改项
            try:
                modify_mes = self.find('.//*[@id="js_modify_time"]/..')
                body_displayed_para.append(modify_mes)
            except NoSuchElementException:
                pass
            
            all_content = self.finds('.//div[@id="js_content"]/*')
            for i in range(len(all_content)):
                try:
                    if all_content[i+j].location['y']==end_location_y:
                        break
                except IndexError:
                    print('#####反选文章内容时，底部界限没有找到。')
            else:
                print('#####反选文章内容时，底部界限没有找到。')
            
            rear_displayed_paras = all_content[i+j+1:]

            all_invisible_list = head_displayed_paras[0:z] + body_displayed_para + rear_displayed_paras
            for i in all_invisible_list:
                self.display_element(i)

            make_sure = self.find('.//p[text()="微信扫一扫"]')
            if make_sure.is_displayed():
                print('#####文章二维码部分可能没有删除干净。\n')

            body = './/div[@id="js_content"]'
            body = (By.XPATH,'.//div[@id="js_content"]')
            self.ctrl_c(body)

    def _load_full_page(self):
        imgs=[]
        if self.message['source']=='weixin':
            #没加载的图片的class="img_loading"，文章结尾的特征是p[contains(@style,'text-align: center')]
            imgs_1 = self.driver.find_elements_by_xpath('//div[@id="js_content"]/p//img')
            imgs_2 = self.driver.find_elements_by_xpath('//div[@id="js_content"]/section/img')
            imgs_3 = self.driver.find_elements_by_xpath('//div[@id="js_content"]/section/span/img')
            imgs = imgs_1 + imgs_2 + imgs_3
            #self.message['imgs_num'] = len(imgs)
            for img in imgs:
                img.location_once_scrolled_into_view
                for i in range(20):#不知道为什么等第一张图片载入需要很久，算然第一张图片很早就出现了
                    time.sleep(0.2)
                    if img.get_attribute('class') != 'img_loading':
                        break
                    int(i)
            self.scroll_to_bottom()
            
        elif self.message['source']=='tencent':
            imgs = self._wait_for_all(10,(By.XPATH,'.//div[@class="melo-section"]/div//img[contains(@src,"qqadapt")]'))

        return (len(imgs),imgs)
    
    #从腾讯文档中获取新文章信息
    def load_local_essay(self,file_path,log=True):
        "需要电脑上qq处于登陆状态"
        main_path=self.main_path
        self.message={}
        self.driver.maximize_window()

        if log:
            log_res = self._login_tencent_page()
            if not log_res:
                return 

            elif log_res==1:
                self._login_tencent_page()
            
            elif log_res==2:
                self.load_local_essay(file_path)

        self._open_upload_window()

        file_path = self._search_load_essay(file_path,main_path)

        Winhand().upload_file(file_path)#使用pywin32导入

        self._wait_for_uploaded()

        #弹出新窗口
        self.driver.close()
        self.switch(-1)
        #检查是否切换到正确的窗口
        file_name = re.search(r'\\{1}(?P<file_name>[^\\]+?).doc+x*',file_path).group('file_name')
        if file_name in self.driver.title:
            print('已切换到正确窗口。\n')

        self._collect_essay_info()
        return
    
    def _login_tencent_page(self):
        self.driver.get('https://docs.qq.com/desktop/?')
        try:
            self.switch_to_frame()
            try:
                self.driver.find_element_by_xpath('.//div[@class="qlogin_list"]/a').click()
            except NoSuchElementException:
                ans = input('您的qq可能没有登录,请登录后再试。(回车继续，按任意字母推出。)\n')
                if ans:
                    return 0
                else:
                    return 1
            try:
                self._wait_for(5,(By.XPATH,'.//div[@class="new-button-wrap"]/button')).click()
                return 3
            except TimeoutException:
                ans = input('未能登录成功。（回车重新载入，按任意字母退出）\n')
                if ans:
                    return 0
                else:
                    return 2

            time.sleep(0.3)
        except (TimeoutException,NoSuchElementException):
            print('切换frame失败，请检查网络再试。\n')
            return 0
    
    def _open_upload_window(self):
        try:
            self._wait_for_displayed(1,(By.XPATH,'.//div[@class="new-button-wrap"]/div'))
        except TimeoutException:
            self._wait_for(5,(By.XPATH,'.//div[@class="new-button-wrap"]/button')).click()
        new = self.find('.//div[@class="silder"]//ul/li[@title="导入文档在线编辑"]')
        self._js_click(new)
    
    def _search_load_essay(self,file_path,main_path):
        if '\\' not in file_path:
            first = []
            for i in os.listdir(self.main_path):
                if file_path in i:
                    first.append(i)
            second = []
            for i in first:
                if '.doc' in i:
                    second.append(i)
            if len(second) < 1:
                file_path = input('没有找到文件，请重新输入。(回车退出)\n')
                if file_path:
                    file_path = self._search_load_essay(file_path,main_path)
                else:
                    return
            elif len(second) > 1:
                file_path = input('存在多个搜索结果，请重新输入。(回车退出)')
                if file_path:
                    file_path = self._search_load_essay(file_path,main_path=main_path)
                else:
                    return
            else:
                file_path = os.path.join(main_path,second[0])
                print(file_path)
                print('已选中待上传文件。')

        return file_path
    
    def _wait_for_uploaded(self):
        importer = self._wait_for(4,(By.XPATH,'.//div[@class="content-dialog import-file-dialog "]'))
        while True:
            try:
                importer.is_displayed()
                time.sleep(0.5)
            except StaleElementReferenceException:
                print('导入文件成功。\n')
                break
    
    def _get_title_for_tencent(self):
        paras = self.finds('.//div[@class="melo-section"]/div/div')
        for para in paras:
            text = para.text
            if text:
                return text

    def _get_intro_for_tencent(self,paras,title_id):
        intro_id = 0

        for i,para in enumerate(paras[:10]):

            raw_introduce = para.text
            if '导语' in raw_introduce:
                introduce = re.sub(r'导语(）)?(\))?(\s)*(:|：)\s*','',raw_introduce)
                self.message['introduce'] = introduce.strip()
                intro_id = i+1
                break
            else:
                continue

        else:
            print('没有标志性导语，以标题下面一段处理。\n')
            intro_id = title_id + 1
            self.message['introduce'] = self.find('.//div[@class="melo-section"]/div/div[%d]' %intro_id)
        self.message['intro_id'] = intro_id

    def _get_bold_text_for_tencent(self):
        res = []
        cons = '来自帮宁工作室（gbngzs）的报道'
        try:
            cons_para = self.find('.//div/span[contains(text(),"%s")]' %cons)
            res.append(self._deal_double_space(cons_para.text.strip()))
        except NoSuchElementException:
            print('####没有找到"来自帮宁工作室（gbngzs）的报道"这句话\n')
            print('####以作者下面一段代替:')
            cons_para_id = self.message['author_id']+1
            cons_para = self.find('.//div[@class="melo-section"]/div/div[%d]' %cons_para_id)
            text = cons_para.text
            res.append(self._deal_double_space(text))
            print(text)
            print('')

        author_id = self.message['author_id']
        if author_id>0:
            author_para = self.find('.//div[@class="melo-section"]/div/div[%d]' %self.message['author_id'])
            text = author_para.text
            text = self._deal_double_space(text).strip()
            res.append(text)
        else:
            print('###加粗列表中，作者项为空。')

        return res

    def _collect_essay_info(self):
        self.message['original'] = True
        self.message['source'] = 'tencent'
        self.message['model'] = 'publish'
        self.message['new'] = True
        content = self._wait_for(10,(By.XPATH,'.//div[@class="melo-section"]/div'))
        paras = content.find_elements_by_xpath('./div')
        #获取标题
        title_id = 0#当导语找不到标志时，使用标题下面的一段

        for i,para in enumerate(paras[:10]):
            title = para.text
            if title:
                new_title = self._strip_title(title)
                if new_title:#如果标题没有标志性，以第一段为标题
                    self.message['title'] = new_title
                    title_id = i+1
                    break
        else:
            print('没有找到标志性标题，标题以非空的第一段处理。\n')
            title = self._get_title_for_tencent()
            self.message['title'] = self._add_forhead(title)

        #获取导语
        self._get_intro_for_tencent(paras,title_id)

        #获取作者
        self.message['author'] = self._get_author_for_tencent(paras)
        #获取图片数量

        self.message['imgs_num'],imgs = self._load_full_page()

        self.message['cover_path'] = self._get_cover(imgs)
        self._check_img_and_title()
        self.message['tags'] = self._save_essay_text_and_get_tags()
        self.message['heading'] = self._get_heading_text()
        self.message['bold'] = self._get_bold_text_for_tencent()
        self._check_position()
        self.message['extras'] = self._get_extra_text()

        self._select_area_for_tencent(execute=False)
        #self._get_html()
        self._save_message()
                    
    def _strip_title(self,raw_title):
        try:
            title = re.search(r'GBN.*',raw_title).group()
        except AttributeError:
            title=''
        if not title:
            title = re.sub(r'标题(\s)*(:|：)\s*','',raw_title)
            if title==raw_title:
                return False
        return title.strip()

    def _get_author_for_tencent(self,paras):
        "为了防止导语存在两行，如果直接使用intro_id会出现后半段导语的黏贴，所以采用，作者前的导语"
        for i,para in enumerate(paras[:10]):
            text = para.text
            if text:
                try:
                    author = re.search(r'(作者|文){1}\s*(\||:|：|/){1}\s*(?P<author>.*)',text).group('author')
                    author = author.strip()
                    self.message['author_id'] = i+1
                    # self.message['intro_id'] = re.sub(r'\d+',lambda match:str(int(match.group())-1),author_id)
                    return self._check_author_is_too_long(author)
                except AttributeError:
                    pass
        print('没有找到作者，使用默认作者。')
        self.message['author_id'] = -1
        return '葛帮宁'

    def _check_position(self):

        if self.message['author_id'] - self.message['intro_id'] != 1:
            print('***********************\n导语与作者行位置不正确，\n请注意正文拷贝范围是否正确。\n***********************\n')

    def _get_cover(self,imgs,num=0):

        cover_url = imgs[0].get_attribute('src')
        cover_path = self._save_and_get_cover(cover_url)
        return cover_path
    
    
    def _select_area_for_tencent(self,execute=True):
        self.driver.maximize_window()
        self._load_full_page()
        if execute:
            #self.delete_extra_paras()
            body = (By.XPATH,'.//div[@class="melo-section"]/div/div[2]')
            self.ctrl_c(body)
        else:
            return


    def _modify_double_space(self,matched):
        sub = '&nbsp;'
        text = matched.group()
        res=text[0] + sub*(len(text)-1)
        return res

    def _deal_double_space(self,text):
        res = re.sub(r'\s{2,}',self._modify_double_space,text)
        return res

    def _get_extra_text(self):
        "从腾讯在线文本中可能获得存在连续空格的段落，但是在黏贴到163后，自动将第二个以及后面的空格转化为&nbsp;"
        res = []

        for i in range(0,self.message['intro_id']):
            para = self.find('.//div[@class="melo-section"]/div/div[%d]' %(i+1))
            text = para.text
            # text = self._get_tag_html(para)
            # text = self._strip_tags_in_text(text)
            if text:
                # text = self._deal_double_space(text)
                res.append(text.strip())

        return res
               
    def delete_extra_paras(self):
        "使用html删除，页面会被锁死，无法选中，display它们也不行"
        inner_htmls=[]
        for i in range(0,self.message['intro_id']):
            para = self.find('.//div[@class="melo-section"]/div/div[%d]' %(i+1))
            if para.text == self.message['extras'][i]:
                inner_htmls.append(self._get_tag_html(para))

    
    def _select_para_by_id(self,para_id,step):
        "para_id表示腾讯文档里面ID段落id，step表示在该段落上上下移动的行数，就是把一个str中数字加一个int的操作"
        str_add_int = lambda a,b: str(int(a.group('value')) + b)
        from functools import partial
        move_with_step = partial(str_add_int,b=step)
        res = re.sub(r'(?P<value>\d+)', move_with_step, para_id)
        return res
    #从腾讯文档中获取新文章信息    

    #直接获取永久链接得到文章信息
    def get_new_essay_by_url(self,url=None,test=False):
        self.message={}
        message = {}
        if url:
            self.driver.get(url)
        else:
            url = self.driver.current_url
        self.message['source'] = 'weixin'
        self.message['model'] = 'publish'
        if test:
            self.message['new'] = False
        else:
            self.message['new'] = True
        message['url'] = url
        message['introduce'] = self._get_intro()
        message['title'] = self._get_title()
        message['author'] = self._strip_author()
        message['imgs_num'] = self._load_full_page()[0]
        message['cover_path'] = self._save_and_get_cover()
        message['heading'] = self._get_heading_text()
        message['bold'] = self._get_bold_text()
        message['tags'] = self._save_essay_text_and_get_tags()
        message['date'] = self._get_news_date()
        message['extras'] = []

        self._add_message_to_attr(message)

        self._check_img_and_title()

        self._select_area(execute=False)

        self._save_message()

    def _strip_author(self):
        if self.message['source']=='weixin':
            text = self._wait_for(5,(By.XPATH,'//div[@id="meta_content"]')).text
            try:
                author = re.search(r'(原创：)*\s*(?P<author>.+)(帮宁)+',text).group('author').strip()
                self.message['original'] = True
            except AttributeError:
                text = self.find('.//div[@id="js_content"]').text
                author = re.search(r'(作者)\s*\|{1}\s*(?P<author>.+)',text).group('author').strip()
                self.message['original'] = True

            return self._check_author_is_too_long(author)
        else:
            print('不是来自微信的文章。')

    def _get_intro(self):
        intro = re.search(r'msg_desc+\s*=+\s*"(?P<intro>.+)"',self.driver.page_source).group('intro')
        return intro

    def _get_title(self):
        title= re.search(r'msg_title+\s*=+\s*"(?P<title>.+)"',self.driver.page_source).group('title')
        return title


    def _save_and_get_cover(self,cover_url=None):
        main_path=self.cover_path
        if not cover_url:
            cover_url = self.find('.//div[@id="js_content"]//img').get_attribute('data-src')
            #print(cover_url)
            #cover_url = re.search(r'msg_cdn_url+\s*=+\s*"(?P<url>.+)"',self.driver.page_source).group('url')
        cover = requests.get(cover_url)
        cover.raise_for_status()
        file_name = str(int(time.time())) + '.jpg'
        cover_path = os.path.join(main_path,file_name)
        with open(cover_path,'wb') as f:
            f.write(cover.content)
        return cover_path

    def _save_essay_text_and_get_tags(self):
        "将文章写入txt,以便后来生成tag"
        content_path = self.content_for_tag_path
        if self.message['source'] == 'weixin':
            paras = self.driver.find_elements_by_xpath('//div[@id="js_content"]/p/span')
        elif self.message['source'] == 'tencent':
            paras = self.driver.find_elements_by_xpath('.//div[@class="melo-section"]/div/div')
        with open(content_path,'w') as f:
            for para in paras:
                text = para.text
                if text:
                    f.write(text.encode("gbk", 'ignore').decode("gbk", "ignore"))
        tags = self.generate_tags()
        return tags

    def _get_tag_html(self,element):
        js = 'return arguments[0].innerHTML'
        return self.driver.execute_script(js,element)

    def _insert(self,word,target):
        fragments = word.split(target)
        for i in range(len(fragments)//2):
            fragments[i*2] += '\\'
        return target.join(fragments)

    def escape_word(self,word):
        "将字符变量引用到正则表达式中，如果不进行转义，会出现错误。"
        re_escape = ('\\','^','_','$','|','@','[',']','{','}','(',')')
        for i in re_escape:
            if i in word:
                word = self._insert(word,i)
        return word

    def _get_text_from_html(self,html):
        "防止还有嵌套的子元素，不过暂时没必要"
        try:
            res = re.search(r'>?(?P<text>[^<]+)(</)?',html).group('text')
        except (AttributeError,TypeError):
            return None
        return res

    def _strip_tags_in_text(self,text):
        text = re.sub(r'<{1}[^>]*?>{1}','',text)
        return text
    
    def _get_heading_text(self):
        "认为字体为font-size: 18px，颜色为rgb(255, 169, 0)的段落为一级标题"
        if self.message['source'] == 'tencent':
            return []
        content = self.driver.find_element_by_xpath('//div[@id="js_content"]')
        content_html = self._get_tag_html(content)
        target = r'<span[^>]*>(\d{1,2}\.?)</span>'
        res = re.findall(target,content_html)
        return res

    def _get_bold_text(self):
        res = []

        paras = self.driver.find_elements_by_xpath('//div[@id="js_content"]/p/span')
        for i in paras[:10]:
            if 'rgb(136, 136, 136)' in i.get_attribute('style'):
                j = i.find_element_by_xpath('./..')
                text = self._get_tag_html(j)
                if text:
                    text = self._strip_tags_in_text(text)
                    res.append(text)
        res = list(set(res))

        for i in res:
            if not i:
                res.remove(i)
        return res

    def _add_message_to_attr(self,message):
        for i in message:
            self.message[i] = message[i]

    def _get_news_date(self):
        try:
            date = self.find('.//span[@id="js_modify_time"]').text
        except NoSuchElementException:
            show_date = self._wait_for(3,(By.XPATH,'.//em[@id="publish_time"]'))
            self._js_click(show_date)
            time.sleep(0.5)
            date = self._wait_for(3,(By.XPATH,'.//em[@id="publish_time"]')).text
        return date
#new_essay

#publish

    def _open_publish_page_and_get_dict(self):
        for i in publish_url:
            self.open_new_window(publish_url[i],quick_model=True)
            time.sleep(1.5)
        D = self.get_handle_dict()
        return D

                
    #for test   
    def get_webs(self,again=True):
        # ans = input("请先确保message正确设置。(回车退出)\n")
        # if not ans:
        #     return

        for i in log_url:
            self.webs[i] = map_name_class(i)(self.driver,self.message)
        
    def refresh_handle_dict(self):
        self.handle_dict = self.get_handle_dict()
        try:
            self.switch(self.handle_dict['qq'])
            url = self.driver.current_url
            if self.message['source']=='weixin':
                char = '//mp.weixin.qq.com/'
            elif self.message['source']=='tencent':
                char = '//docs.qq.com/'
            else:
                print('文章来源不明。\n')
                return 
            if char in url:
                self.main_handle= self.handle_dict['qq']
            if self.message['model']!='collect':
                del self.handle_dict['qq']
        except KeyError:
            pass

    def check_logged(self,handle_dict=None):
        ready=True
        if not handle_dict:
            handle_dict = self.handle_dict
        
        for i in handle_dict:
            self.switch(handle_dict[i])
            logged = self.webs[i].is_logged()
            if not logged:
                print('%s没有登录。\n' %map_eng_zh[i])
                try:
                    self.webs[i].login()
                except Exception:
                    print('%s自动登录出错' %map_eng_zh[i])
                ready=False
        return ready  

    def paste_title(self):
        for i in self.handle_dict:
            self.switch(self.handle_dict[i])
            new_handle = self.webs[i].paste('title')
            if new_handle:
                self.handle_dict[i] = new_handle
            time.sleep(0.8)

    def paste_body(self):
        body_list  = list(self.handle_dict.keys())
        body_list.remove('163')
        body_list.remove('dayu')
        for i in body_list:
            self.switch(self.handle_dict[i])
            self.webs[i].paste('body')
            time.sleep(0.8)
    
    def modify_content(self):
        for i in self.handle_dict:
            if i=='dayu':
                continue
            self.switch(self.handle_dict[i])
            try:
                self.webs[i].modify_content()
            except Exception:
                print('来自"%s"的错误信息:\n' %map_eng_zh[i])
                print(traceback.format_exc())
            time.sleep(1)

    def check_box(self):
        handle_dict=copy.copy(self.handle_dict)
        if self.message['source']=='weixin':
            del handle_dict['yidianzixun']

        for i in handle_dict:
            self.switch(handle_dict[i])
            try:
                self.webs[i].check_box()
            except Exception:
                print('来自"%s"的错误信息:\n' %map_eng_zh[i])
                print(traceback.format_exc())
            time.sleep(1)

    def publish(self):
        handle_dict=copy.copy(self.handle_dict)
        if self.message['source']=='weixin':
            del handle_dict['yidianzixun']
        
        for i in handle_dict:
            self.switch(handle_dict[i])
            try:
                self.webs[i].publish()
            except Exception:
                print('来自"%s"的错误信息:\n' %map_eng_zh[i])
                print(traceback.format_exc())
            time.sleep(0.8)
  
    def check_published(self):
        print('正在检查是否正常发布...\n')
        handle_dict=copy.copy(self.handle_dict)
        if self.message['source']=='weixin':
            del handle_dict['yidianzixun']

        for i in handle_dict:
            try:
                self.switch(handle_dict[i])
                if i=='youcheyihou':
                    print('####网站:%s发布失败' %map_eng_zh[i])
            except NoSuchWindowException:
                if i=='youcheyihou':
                    continue
                else:
                    print('来自"%s"的错误信息:\n' %map_eng_zh[i])

            j = 0
            while True:
                j+=1
                url = self.driver.current_url
                if self.webs[i].check_published(url):
                    break
                elif j<4:
                    time.sleep(1)
                else:
                    print('####网站:%s发布失败' %map_eng_zh[i])
                    break
            
    def deal_163(self):
        self.switch(self.handle_dict['163'])
        w_163 = self.webs['163']
        w_163.paste('body')
        time.sleep(1)
        w_163.copy()

    def deal_youcheyihou(self):
        print('正在处理车友号...\n')
        web = 'youcheyihou'
        self.switch(self.handle_dict[web])
        youche = self.webs[web]
        youche.paste('body')
        time.sleep(1)
        youche.copy()

    def deal_autohome(self):
        print('正在处理车家号...\n')
        web = 'autohome'
        self.switch(self.handle_dict[web])
        autohome = self.webs[web]
        autohome.paste('body')
        time.sleep(1)
        autohome._modify_bold()#根据message修改bold中空格与&nbsp;混杂的情况
        autohome.copy()

    def deal_dayu(self):
        print('正在处理大鱼号...\n')
        self.switch(self.handle_dict['dayu'])
        dayu = self.webs['dayu']
        dayu.paste('body')
        dayu.wait_for_content()
        dayu.modify_content()
        dayu.copy()
        #self.webs['dayu'].copy()

    def step_1(self):
        print("初始化句柄集与webs集")
        self.refresh_handle_dict()
        self.get_webs()
    
    def step_2(self):
        print("检查登陆情况并黏贴标题。")
        res = self.check_logged()
        if res:
            time.sleep(1)
            ans=''
        else:
            ans = input('登陆存在问题，如解决按回车继续黏贴标题，\n按任意一个字母退出。\n')
        if not ans:
            self.refresh_handle_dict()
            self.paste_title()
        else:
            return 

    def step_3(self):
        try:
            special_webs = ('baidu','sina','qutoutiao','163')
            normal_webs = []
            main_webs = ['youcheyihou','dayu','autohome']
            print("处理有车、车家号与大鱼号，将准正文复制到剪切板。")
            self.switch(self.main_handle)
            if self.message['source']=='tencent':
                self._select_area_for_tencent()
            elif self.message['source']=='weixin':
                self._select_area()
            else:
                print('文章来源不明。\n')
                return 
            self.deal_youcheyihou()
            
            time.sleep(1.5)
            self.deal_autohome()

            for i in self.handle_dict:
                if i in special_webs:
                    self.switch(i)
                    self.webs[i].paste('body')
                    time.sleep(0.8)
                else:
                    normal_webs.append(i)
                
            if self.message['source']=='tencent':
                normal_webs.append('youcheyihou')

            for i in main_webs:
                if i in normal_webs:
                   normal_webs.remove(i)

            self.deal_dayu()

            for i in normal_webs:
                self.switch(i)
                self.webs[i].paste('body')
                time.sleep(0.8)
        except Exception:
                print('来自"%s"的错误信息:\n' %map_eng_zh[i])
                print(traceback.format_exc())

    def step_4(self):
        print("修改正文以及设置选项")
        #self.paste_body()
        self.modify_content()
        self.check_box()
        # ans = input('已修改了正文，请进一步纠正后按回车继续。(按任意字母退出)\n')
        # if not ans:
        #     self.check_box()
        # else:
        #     return

    def step_5(self):
        print('发表。')
        self.publish()

    def step_6(self):
        self.check_published()

    def steps(self,step=True):
        print('打开网页中...')
        self._open_webs()

        print('正在处理第一步。\n')
        self.step_1()

        print('正在处理第二步。\n')
        self.step_2()

        if step:
            ans = input('输入任意字母退出，回车继续。\n')
            if ans:
                print('第二步进行完毕。\n')
                return
        else:
            print('第二步进行完毕。\n')

        print('正在处理第三步——复制粘贴正文...\n')
        self.step_3()

        if step:
            ans = input('输入任意字母退出，回车继续。\n')
            if ans:
                print('第三步进行完毕。\n')
                return
        else:
            print('第三步进行完毕。\n')

        print('正在处理第四步——修改字体与勾选复选框...\n')
        self.step_4()

        if step:
            ans = input('输入任意字母退出，回车继续。\n')
            if ans:
                print('第四步进行完毕。\n')
                return
        else:
            print('第四步进行完毕。\n')

        print('正在处理第五步——发布...\n')
        self.step_5()

        print('第五步进行完毕。\n')

        print('正在处理第六步——检查发布是否成功...\n')
        self.step_6()
        print('第六步进行完毕。\n')

        print('######本次文章转发结束#######\n')

#publish

#cookie
    def get_cookies(self,web_name):
        cookie = self.driver.get_cookies()
        if cookie:
            jsonCookies = json.dumps(cookie)
            with open(r'cookies\%s.json' % web_name, 'w') as f:
                f.write(jsonCookies)
            return True
        else:
            return False
    
    def refresh_cookie_by_hand(self,cookie_dict,domain):
        cookies = []
        for i in cookie_dict:
            cookie = dict()
            cookie['name'] = i
            cookie['value'] = cookie_dict[i]
            cookie['path']  ='/'
            cookie['domain'] = domain
            cookie['expires'] = None
            cookies.append(cookie)
        for i in cookies:
            if i['domain'].find('.') == 0:
                domain  = i['domain']
                break
        else:
            print("没有以'.'开头的域名。\n")

        end = domain.find('.com')
        if end==-1:
            end = domain.find('.net')
            if end == -1:
                print('没有找到域名中的特征字段。\n')
        start = domain.rfind('.',0,end) + 1
        file_name = domain[start:end]
        cookie_list_path = r'C:\Users\Administrator\Desktop\python\习题\项目\cookies\test_2'
        cookie_path  = os.path.join(cookie_list_path,'%s.json' %file_name)
        if os.path.exists(cookie_path):
            ans = input('该cookie--%s.json--会被覆盖，请确定名称是否正确。\n(确认按回车，取消按字母再键回车)\n' %file_name)
            if ans:
                return None
        with open(cookie_path,'w') as f:
            f.write(json.dumps(cookies))
            return True
        
    def login_with_cookies(self,logurl,ready=False):
        web_name = ''
        for cookies in os.listdir('cookies'):
            cookie_name = cookies.split('.')[0]
            print('cookie_name: %s' % cookie_name)
            if cookie_name in logurl:
                web_name = cookie_name
                break
        else:
            print('No cookies for url %s.' % logurl)
        if ready:
            pass
        else:
            self.driver.get(logurl)
        #self.open_new_window(logurl)
        cookie = open(r'C:\Users\Administrator\Desktop\python\习题\项目\cookies\%s.json' % web_name,'r').read()
        cookie = json.loads(cookie)
        for c in cookie:
            self.driver.add_cookie(c)
        self.driver.refresh()
        
    def load_cookies(self,cookie_list_path=r'C:\Users\Administrator\Desktop\python\习题\项目\cookies'):
        #注意，加载cookie时需要打开一个具体网页
        for cookie_file in os.listdir(cookie_list_path):
            cookie_path =  os.path.join(cookie_list_path,cookie_file)
            if os.path.isfile(cookie_path):
                print('正在加载 %s ...\n' %cookie_file)
                cookies = json.loads(open(cookie_path,'r').read())
                for c in cookies:
                    self.driver.add_cookie(c)
        print('已加载所有cookies。\n')

    def load_cookie_by_name(self,cookie_name,cookies_path = r'C:\Users\Administrator\Desktop\python\习题\项目\cookies\test_2'):
        path = os.path.join(cookies_path,'%s.json' %cookie_name)
        if os.path.exists(path):
            cookie = open(path,'r').read()
            cookies = json.loads(cookie)
            if isinstance(cookies,list):
                for c in cookies:
                    self.driver.add_cookie(c)
                if cookie_name=='toutiao':
                    time.sleep(2)
                    login = self._wait_for(5,(By.XPATH,'.//div[@class="standard-content in"]/img[3]'))
                    self.compulsive_click(login)

                return True 
            else:
                local_storage = cookies
                for key in local_storage:
                    self.driver.execute_script("window.localStorage.setItem('%s','%s');" %(key, local_storage[key]))
                return True 
        else:
            print('暂无%s的cookie。\n' %cookie)  
            return False
    
    def load_local_storage(self,path = r'C:\Users\Administrator\Desktop\python\习题\项目\cookies\test_2'):
        domain = self.driver.current_url
        name = self.get_keyword_from_domain(domain)
        local_storage = json.loads(open(os.path.join(path,'%s.json' %name),'r').read())
        for key in local_storage:
            self.driver.execute_script("window.localStorage.setItem('%s','%s');" %(key, local_storage[key]))
            
    def get_local_storage(self,path = r'C:\Users\Administrator\Desktop\python\习题\项目\cookies\test_2'):
        domain = self.driver.current_url
        name = self.get_keyword_from_domain(domain)
        local_storage =dict()
        keys = self.driver.execute_script( \
            "var ls = window.localStorage, keys = []; " \
            "for (var i = 0; i < ls.length; ++i) " \
            "  keys[i] = ls.key(i); " \
            "return keys; ")
        for i in keys:
            value = self.driver.execute_script("return localStorage.getItem('%s')" %i)
            local_storage[i]  =value
        local_storage_path = os.path.join(path,'%s.json' %name)
        with open(local_storage_path,'w') as f:
            f.write(json.dumps(local_storage))
        return True
        
    def expiry_of_cookie(self):#返回在半小时后过期的cookie名单
        died_cookie = []
        live_cookie = []
        now = time.time() - 1800
        os.chdir(r'C:\Users\Administrator\Desktop\python\习题\项目')
        for cookie_json in os.listdir('cookies'):
            cookie_name = cookie_json.split('.')[0]
            cookie = open(r'cookies\%s' % cookie_json,'r').read()
            cookies = json.loads(cookie)
            #print(cookies[0]['domain'],end=':')
            expiries = []
            for c in cookies:
                try:
                    temp = c['expiry']
                    expiries.append(temp)
                except KeyError:
                    pass
            #expiries_of_all_cookies[cookie_name] = expiries[0]
            expiries.sort()
            if expiries[0] < now:
                died_cookie.append(cookie_name)
            else:
                live_cookie.append(cookie_name)
        return [tuple(died_cookie),tuple(live_cookie)]
#cookie


    def get_branch(self):
        return json.loads(open(self.branch_path).read())

    def search_handle_by_title(self,title,switch=True):
        current = self.driver.current_window_handle
        for i in self.driver.window_handles:
            self.driver.switch_to.window(i)
            if title == self.driver.title:
                if not switch:
                    self.driver.switch_to.window(current)
                return i
        
    def get_new_handle(self,current_handles=None):
        if current_handles==None:
            return self.driver.window_handles[-1]
        else:
            new_handles = self.driver.window_handles
            res = list(set(new_handles) - set(current_handles))[0]
            return res
    
    def attr(self,w,a):
	    return w.get_attribute(a)
    
    def switch(self,num):
        if isinstance(num,str):
            if num[:8]=='CDwindow':
                self.driver.switch_to.window(num)
            else:
                try:
                    self.driver.switch_to.window(self.handle_dict[num])
                except KeyError:
                    print('无法识别所要转到的标签页。\n')
                    return
        elif isinstance(num,int):
	        self.driver.switch_to.window(self.driver.window_handles[num])
        else:
            print('只能输入句柄字符串与整型')

    def location(self,w):
        js = "var q=document.documentElement.scrollTop=%d" %w.location['y']
        self.driver.execute_script(js)
        return w.location

    def get_to_bottom(self,content_loactor):#切到发布界面
        #self._wait_for(3,(By.XPATH,'//div[@id="container"]/p'))
        paras = self.driver.find_elements(content_loactor[0],content_loactor[1])
        end = paras[-1]
        ActionChains(self.driver).move_to_element(end).click(end).\
            key_down(Keys.PAGE_DOWN).key_up(Keys.PAGE_DOWN).key_down(Keys.ENTER).\
            key_up(Keys.ENTER).perform()
         
    def open_new_window(self,url,current_handles=None,quick_model=False):#在非快速模式下，打开新窗口并转入，并返回此窗口的handls
        if quick_model:
            js = 'window.open("%s")' %url
            current_handles = self.driver.window_handles
            self.driver.execute_script(js)
            self.get_new_handle(current_handles)

        else:
            js = 'window.open("")'
            self.driver.execute_script(js)#
            current_handle = self.get_new_handle(current_handles)
            self.driver.switch_to.window(current_handle)
            self.driver.get(url)#只有当driver.get(url)得到服务器响应了，该新建窗口的id才会被加入windows_handles中
            return current_handle
        #return self.driver.current_window_handle
        # windows = self.driver.window_handles
        # self.driver.switch_to.window(windows[-1])
    
    def delete_info(self,web_element):
        web_element.send_keys(Keys.CONTROL+'a')
        web_element.send_keys(Keys.DELETE)

    def scroll_to_bottom(self):
        js="var q=document.documentElement.scrollTop=100000"
        self.driver.execute_script(js)
    
    def scroll_to_top(self):
        js="var q=document.documentElement.scrollTop=0"
        self.driver.execute_script(js)


    def ctrl_v(self,body_locator,introduce=None):#点击-清空-复制
        body = self._wait_for(2,body_locator)
        self.compulsive_click(body)
        if introduce == None:
            ActionChains(self.driver).key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL)\
                .key_down(Keys.BACKSPACE).key_up(Keys.BACKSPACE).pause(0.3).key_down(\
                    Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()
        else:
            ActionChains(self.driver).key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL)\
                .key_down(Keys.BACKSPACE).key_up(Keys.BACKSPACE).pause(0.3).send_keys(\
                    introduce).key_down(Keys.ENTER).key_up(Keys.ENTER).key_down(\
                        Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()

    def ctrl_c(self,body_locator):#全选复制
        try:
            body = self._wait_for_clickable(2,body_locator)

        except TimeoutException:
            body = self._wait_for(1,body_locator)
        #body.location_once_scrolled_into_view
        self.compulsive_click(body)
        
        #self.focus_on(body)
        time.sleep(0.5)
        ActionChains(self.driver).key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).\
            key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()

    def _wait_for(self,time,locator):
        return WebDriverWait(self.driver,time,0.2).until(EC.presence_of_element_located(locator))

    def _wait_for_all(self,time,locator):
        return WebDriverWait(self.driver,time,0.2).until(EC.presence_of_all_elements_located(locator))
    
    def _wait_for_all_displayed(self,time,locator):
        return WebDriverWait(self.driver,time,0.2).until(EC.visibility_of_all_elements_located(locator))
    
    def _wait_for_displayed(self,time,locator):
        return WebDriverWait(self.driver,time,0.2).until(EC.visibility_of_element_located(locator))
    
    def _wait_for_clickable(self,time,locator):
        return WebDriverWait(self.driver,time,0.2).until(EC.element_to_be_clickable(locator))

    def compulsive_click(self,web_element):
        for i in range(10):
            try:
                try:
                    ActionChains(self.driver).move_to_element(\
                        web_element).click(web_element).perform()
                    break
                except Exception:
                    web_element.click()
                    break
            except Exception:
                time.sleep(0.2)
            int(i)

    def dict_attr(self,text):#获取web_elemennt的style，并转化成字典
        mass = text.split()
        keys = []
        values = []
        length = len(mass)
        if length%2 != 0:
            print('The attribute text is not complete.')
            return 
        for i in range(0,length,2):
            keys.append(mass[i][:-1])
            values.append(mass[i+1][:-1])
        return dict(zip(keys,values))

    def print_message(self):
        for i in self.message:
            if i!='html':
                print('%s :%s' %(i,self.message[i]))

    def remove_element_by_js(self,element):
        js = 'arguments[0].parentNode.removeChild(arguments[0])'
        self.driver.execute_script(js,element)

    def _change_html(self,element,content):
        js = 'arguments[0].innerHTML=arguments[1]'
        self.driver.execute_script(js,element,content)

    
############################# tools ###########################################################


    




	
    





        
    




	
    
